#include "EPollPoller.h"
#include "Logger.h"
#include "Channel.h"
#include "Timestamp.h"
#include<unistd.h>
#include <sys/epoll.h>
#include<cstring>
// channel 未添加到poller中
const int kNew = -1; // channel的成员index_ = -1
// channel 已添加到poller中
const int kAdded = 1;
// channel从poller中删除
const int kDeleted = 2;

EPollPoller::EPollPoller(EventLoop* loop) // epoll_create
   : Poller(loop), epollfd_(::epoll_create1(EPOLL_CLOEXEC)), events_(kInitEventListSize) // vector<epoll_event>
{
    if (epollfd_ < 0)
    {
        LOG_FATAL("epoll_create errir:%d \n", errno);
    }
} // epoll_create
EPollPoller::~EPollPoller()
{
    // 编译器检查是否有实现，基类是否是virtual
    ::close(epollfd_);
}

// poll 主要调用epoll_wait ,moduo 库用的是LT模式,activeChannels 是给到EventLoop的
Timestamp EPollPoller::poll(int timeoutMs, ChannelList *activeChannels)
{
    // 实际上使用LOG_DEBUG更加合理
    LOG_INFO("func=%s => fd total count:%d\n",__FUNCTION__, channels_.size());
    // 我们这里用的是vector，所以需要向下面这样写
    int numEvents = ::epoll_wait(epollfd_, &*events_.begin(), static_cast<int>(events_.size()), timeoutMs);
    LOG_INFO("func=%s => epollfd_ is :%d\n",__FUNCTION__,epollfd_);
    // poll在多个线程可能都会被调用，所以提前保存一份
    int saveErrno = errno;
    Timestamp now(Timestamp::now());
    // 事件就绪后，记录时间戳，然后将revetns记录到
    if (numEvents > 0)
    {
        // 已经发生过了事件
        LOG_INFO("%d events happened \n", numEvents);
        fillActiveChannels(numEvents, activeChannels);
        // 这一轮所有监听的events都上来了，底层的就绪队列可能很大，所以此时需要扩容
        if (numEvents == events_.size())
        {
            events_.resize(events_.size() * 2);
        }
    }
    else if (numEvents == 0)
    {
        LOG_DEBUG("%s timeout! \n", __FUNCTION__);
    }
    else
    {
        if (saveErrno != EINTR)
        {
            errno = saveErrno;
            LOG_ERROR("EPollPoller::poll()");
        }
    }
    return now;
}
// 对应epoll_ctl
void EPollPoller::updateChannel(Channel *channel)
{
    const int index = channel->index();
    LOG_INFO("func=%s => fd=%d events=%d index=%d \n", __FUNCTION__, channel->fd(), channel->events(), index);
    if (index == kNew || index == kDeleted)
    {
        // 没有添加过的状态就是kNew,原来删除的
        if (index == kNew)
        {
            int fd = channel->fd();
            channels_[fd] = channel;
        }
        channel->set_index(kAdded);
        update(EPOLL_CTL_ADD, channel);
    }
    else // channel 已经在poller上注册过了
    {
        int fd = channel->fd();
        if (channel->isNoneEvent())
        {
            update(EPOLL_CTL_DEL, channel);
            channel->set_index(kDeleted);
        }
        else
        {
            // 对某些事件感兴趣
            update(EPOLL_CTL_MOD, channel);
        }
    }
}
void EPollPoller::removeChannel(Channel *channel)
{
    int fd = channel->fd();
    channels_.erase(fd); // 删除map中映射

    LOG_INFO("func=%s => fd=%d  \n", __FUNCTION__, channel->fd());

    int index = channel->index();
    if (index == kAdded) // 如果还是在状态2，就删掉
    {
        update(EPOLL_CTL_DEL, channel);
    }
    channel->set_index(kNew); // 设置状态为可添加
}
// ChannelList 是vector
// ChannelMap 是 unordered_map
// 填写活跃的连接,EPollPoller:: 注意加上！
void EPollPoller::fillActiveChannels(int numEvents,ChannelList* activeChannels) const
{
    for (int i = 0; i < numEvents; ++i)
    {
        // 隐式类型转化
        Channel *channel = static_cast<Channel *>(events_[i].data.ptr);
        channel->set_revents(events_[i].events);
        // 事件就在这里了。
        activeChannels->push_back(channel);
    }
}

// 更新channel通道 epoll_ctl add/mod/del
void EPollPoller::update(int operation, Channel *channel)
{
    epoll_event event;
    ::memset(&event, 0, sizeof(event));
    int fd = channel->fd();
    event.events = channel->events();
    event.data.fd = fd;
    event.data.ptr = channel;


    if (::epoll_ctl(epollfd_, operation, fd, &event) < 0)
    {
        if (operation == EPOLL_CTL_DEL)
        {
            LOG_ERROR("epoll_ctl del error %d\n", errno);
        }
        else
        {
            LOG_FATAL("epoll_ctl add/mod error%d\n", errno);
        }
    }
}